package com.hibase.core.excel.data;

import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.hibase.core.excel.annotation.ExcelProperty;
import com.hibase.core.excel.context.AnalysisContext;
import com.hibase.core.excel.enums.RowTypeEnum;
import com.hibase.core.excel.util.JavassistUtil;
import com.hibase.core.excel.validator.ValidatorUtils;
import com.hibase.core.excel.vo.ErrorMessage;
import com.hibase.core.excel.vo.dynamic.DynamicExcelColumnResult;
import com.hibase.core.excel.vo.dynamic.DynamicExcelResult;
import com.hibase.core.excel.vo.dynamic.DynamicExcelRowResult;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

/**
 * 根据配置模板读取数据数据分析处理器
 *
 * @author <a href="mailto:xiongliyi@hichain.com">Ian Xiong</a>
 * @since 1.4.35-V2
 */
@Slf4j
public class HibaseAnalysisProcessor extends ReadAnalysisProcessor<Object> {
    private final DynamicExcelResult data = new DynamicExcelResult() {
        {
            setRows(Lists.newArrayList());
            setData(Lists.newArrayList());
        }
    };
    private final List<ErrorMessage> errors = Lists.newArrayList();
    private Map<String, Object> defaultValueMap;

    public void setDefaultValueMap(Map<String, Object> defaultValueMap) {
        this.defaultValueMap = defaultValueMap;
    }

    @Override
    public void invoke(Object data, AnalysisContext analysisContext) {
        Integer readRowIndex = analysisContext.readRowHolder().getRowIndex();

        if (RowTypeEnum.EMPTY.equals(analysisContext.readRowHolder().getRowType())) {
            log.debug("Empty row!");
            if (analysisContext.readWorkbookHolder().getIgnoreEmptyRow()) {
                return;
            }
        }


        Map<String, String> violations = ValidatorUtils.validateEntity(data);
        if (!violations.isEmpty()) {
            errors.add(new ErrorMessage(readRowIndex, violations));
        } else {
            // 详情数据（包含行号、列号、字段名称、字段类型）
            this.data.getRows().add(getDetail(readRowIndex, data));

        }
    }

    /**
     * 获取行记录详情
     *
     * @param readRowIndex 行号
     * @param data         easyexcel 分析结果集
     * @return 返回行记录详情
     */
    @SneakyThrows
    private DynamicExcelRowResult getDetail(Integer readRowIndex, Object data) {

        // column result
        List<DynamicExcelColumnResult> columnResults = Lists.newArrayList();

        Class<?> ctClass = data.getClass();
        Field[] fields = ctClass.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            DynamicExcelColumnResult columnInfo = new DynamicExcelColumnResult();

            ExcelProperty excelProperty = (ExcelProperty) fields[i].getDeclaredAnnotations()[0];
            int columnNumber = excelProperty.index();


            String fieldName = fields[i].getName();
            String methodName = JavassistUtil.GET_PREFIX + StrUtil.upperFirst(fieldName);
            Object value = ctClass.getMethod(methodName).invoke(data, null);


            // set default value
            if (value == null && defaultValueMap.containsKey(fieldName)) {
                Object defaultValue = defaultValueMap.get(fieldName);
                columnInfo.setDefaultValue(defaultValue);
                columnInfo.setBeDefaultValue(Boolean.TRUE);

                fields[i].set(data, defaultValue);
            } else {
                columnInfo.setBeDefaultValue(Boolean.FALSE);
            }


            columnInfo.setRowNumber(readRowIndex);
            columnInfo.setColumnNumber(columnNumber);
            columnInfo.setFieldKey(fieldName);
            columnInfo.setFieldType(fields[i].getClass().getName());
            columnInfo.setData(value);

            columnResults.add(columnInfo);
        }


        // row result
        DynamicExcelRowResult rowResult = new DynamicExcelRowResult(readRowIndex,columnResults);

        this.data.getData().add(data);

        return rowResult;
    }


    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        log.debug("Reading excel is complete");
    }


    @Override
    public List<Object> getData() {
        return data.getData();
    }

    @Override
    public List<ErrorMessage> getErrors() {
        return errors;
    }

    public DynamicExcelResult getDynamicResult() {
        return data;
    }
}
